#include "Core\Oatmeal.h"			// standard library include (must be first include)
#include "Core\Internals.h"			// standard include for intenral definitions
#include "IO\Settings.h"			// module to retrieve/set engine settings

////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////// SETTING ROUTINES /////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////

// define an object of the settings container with default values
struct tagGlobalSettings GlobalSettings = OAT_SETTINGS_INIT;

// private routines
#ifdef _WIN32
	static bool _GetWindowsRegValue (const HKEY hReg, const tchar *szSubkey, const tchar *szValue,
									 const DWORD dwType, void *pDest, DWORD dwSize);

	static bool	_SetWindowsRegValue (const HKEY hReg, const tchar *szSubkey, const tchar *szValue,
									 const DWORD dwType, const void *pData, const DWORD dwSize);
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////

/*/
/ / bool
/ /		GetUserValue (const tchar *szSubkey, const tchar *szValue,
/ /			const uint32 nType, void *pDest, const int32 nSize)
/ /
/ /		szSubkey = name of the subkey to look for the values in
/ /		szValue = name of the value to read data from (use NULL for default value)
/ /		nType = type of data to pull: OAT_SERIAL_INT32, OAT_SERIAL_STRING, etc.
/ /		pDest = destination buffer to return the data in, can be of any type
/ /		nSize = size of the destination buffer (buffer size always, not length of chars for string data)
/ /
/ / PURPOSE:
/ /		Function intended to serve as a means to repeat the repeatative operations
/ /		needed to access registry value data frequently from the local user hive.
/ /
/ / NOTE:
/ /		This will prepend company and software name before the subkey that's pass to automatically
/ /		keep the data orginaized in the registry and so the caller needn't worry about it.
/*/

bool
GetUserValue (const tchar *szSubkey, const tchar *szValue,
			  const uint32 nType, void *pDest, const int32 nSize)
{
	tchar szPath[MAX_STRING] = {0};

	// we need to create the string to prepend to the passed subkey (saves time for the caller)
	// to do this, we'll concat the passed value after the company name and app name constants
	_tcscpy_s(szPath, SIZE(szPath), _T("Software\\"));

	// test to make sure the company name was set (remember the string is always allocated)
	if(GlobalSettings.szCompanyName[0] != _T('\0'))
	{
		_tcscat_s(szPath, SIZE(szPath), GlobalSettings.szCompanyName);
		_tcscat_s(szPath, SIZE(szPath), _T("\\"));
	}

	_tcscat_s(szPath, SIZE(szPath), GlobalSettings.szAppName);

	// this can be left null if company/software name is sufficient
	if(szSubkey != NULL)
	{
		_tcscat_s(szPath, SIZE(szPath), _T("\\"));
		_tcscat_s(szPath, SIZE(szPath), szSubkey);
	}

	// since this is a wrapper function, call the real one (platform specific) to get the data
#ifdef _WIN32
	return _GetWindowsRegValue(HKEY_CURRENT_USER, szPath, szValue, (DWORD)nType, pDest, (DWORD)nSize);
#endif
}

///////////////////////////////////////////////////////////////////////////////////////////////////

/*/
/ / bool
/ /		SetUserValue (const tchar *szSubkey, const tchar *szValue,
/ /			const uint32 nType, const void *pDest, const int32 nSize)
/ /
/ /		szSubkey = name of the subkey to set the values in
/ /		szValue = name of the value to save data to (use NULL for default value)
/ /		nType = type of data to save: OAT_SERIAL_INT32, OAT_SERIAL_STRING, etc.
/ /		pData = input buffer that contains the data to serialize
/ /		nSize = size of the input buffer (buffer size always, not length of chars for string data)
/ /
/ / PURPOSE:
/ /		Function intended to serve as a means to repeat the repeatative operations
/ /		needed to access registry value data frequently from the local user hive.
/ /
/ / NOTE:
/ /		This will prepend company and software name before the subkey that's pass to automatically
/ /		keep the data orginaized in the registry and so the caller needn't worry about it.
/*/

bool
SetUserValue (const tchar *szSubkey, const tchar *szValue,
			  const uint32 nType, const void *pData, const int32 nSize)
{
	tchar szPath[MAX_STRING] = {0};

	// we need to create the string to prepend to the passed subkey (saves time for the caller)
	// to do this, we'll concat the passed value after the company name and app name constants
	_tcscpy_s(szPath, SIZE(szPath), _T("Software\\"));

	// test to make sure the company name was set (remember the string is always allocated)
	if(GlobalSettings.szCompanyName[0] != _T('\0'))
	{
		_tcscat_s(szPath, SIZE(szPath), GlobalSettings.szCompanyName);
		_tcscat_s(szPath, SIZE(szPath), _T("\\"));
	}

	_tcscat_s(szPath, SIZE(szPath), GlobalSettings.szAppName);

	// this can be left null if company/software name is sufficient
	if(szSubkey != NULL)
	{
		_tcscat_s(szPath, SIZE(szPath), _T("\\"));
		_tcscat_s(szPath, SIZE(szPath), szSubkey);
	}

	// since this is a wrapper function, call the real one (platform specific) to get the data
#ifdef _WIN32
	return _SetWindowsRegValue(HKEY_CURRENT_USER, szPath, szValue, (DWORD)nType, pData, (DWORD)nSize);
#endif
}

///////////////////////////////////////////////////////////////////////////////////////////////////

/*/
/ / bool
/ /		_GetWindowsRegValue (const HKEY hReg, const tchar *szSubkey, const tchar *szValue,
/ /			const DWORD dwType, void *pDest, DWORD dwSize)
/ /
/ / PURPOSE:
/ /		Local function intended to serve as a means to repeat the repeatative operations
/ /		needed to access registry value data frequently. It should not be called directly.
/ /
/ / COMMENTS:
/ /		This is Windows specific.
/*/

#ifdef _WIN32
static bool
_GetWindowsRegValue (const HKEY hReg, const tchar *szSubkey, const tchar *szValue,
					 const DWORD dwType, void *pDest, DWORD dwSize)
{
	HKEY hKey = NULL;
	bool bReturn = false;
	DWORD dwRealType = 0;

	// test for the required pointers (we don't accept the default value for the registry key as valid on Windows)
	if((pDest != NULL) && (szSubkey != NULL) && (szValue != NULL))
	{
		// open the key in the registry
		if((RegOpenKeyEx(hReg, szSubkey, 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
			&& (hKey != NULL))
		{
			// do not forget, the buffer size for string data must also include a terminating zero
			if(RegQueryValueEx(hKey, szValue, NULL, &dwRealType, (LPBYTE)pDest, &dwSize) == ERROR_SUCCESS)
			{
				// here we add our own bit of type safety (b/c the API really doesn't), if the returned type
				// doesn't match the type passed, we wipe the buffer and return false to avoid a casting err
				if(dwRealType != dwType)
					SecureZeroMemory(pDest, dwSize);
				else
					bReturn = true;
			}

			// clean up
			RegCloseKey(hKey);
		}
	}

	return bReturn;
}
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////

/*/
/ / bool
/ /		_SetWindowsRegValue (const HKEY hReg, const tchar *szSubkey, const tchar *szValue,
/ /			const DWORD dwType, const void *pData, const DWORD dwSize)
/ /
/ / PURPOSE:
/ /		Local function intended to serve as a means to repeat the repeatative operations
/ /		needed to access registry value data frequently. It should not be called directly.
/*/

#ifdef _WIN32
static bool
_SetWindowsRegValue (const HKEY hReg, const tchar *szSubkey, const tchar *szValue,
					 const DWORD dwType, const void *pData, const DWORD dwSize)
{
	HKEY hKey = NULL;
	bool bReturn = false;

	// test for the required pointers (we don't accept the default value for the registry key as valid on Windows)
	if((pData != NULL) && (szSubkey != NULL) && (szValue != NULL))
	{
		// open (or create if it doesn't exist) the key in the registry
		if((RegCreateKeyEx(hReg, szSubkey, 0, NULL, REG_OPTION_NON_VOLATILE,
			KEY_WRITE, NULL, &hKey, NULL) == ERROR_SUCCESS) && (hKey != NULL))
		{
			// do not forget, the buffer size for string data must also include a terminating zero
			if(RegSetValueEx(hKey, szValue, 0, dwType, pData, dwSize) == ERROR_SUCCESS) bReturn = true;

			// clean up
			RegCloseKey(hKey);
		}
	}

	return bReturn;
}
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////